package com.zy.explore.license.interfaces.facade.v1;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.zy.explore.license.domain.mybatis.entity.SysMenu;
import com.zy.explore.license.domain.mybatis.entity.SysRole;
import com.zy.explore.license.domain.mybatis.entity.SysUser;
import com.zy.explore.license.infrastructure.annotation.LoginToken;
import com.zy.explore.license.infrastructure.exception.MessageCode;
import com.zy.explore.license.infrastructure.util.FakerUtil;
import com.zy.explore.license.infrastructure.util.IpUtil;
import com.zy.explore.license.infrastructure.util.JwtUtil;
import com.zy.explore.license.infrastructure.util.StrUtil;
import com.zy.explore.license.interfaces.assembler.SysEventLogAssembler;
import com.zy.explore.license.interfaces.assembler.SysUserAssembler;
import com.zy.explore.license.interfaces.frm.CheckPwdFrm;
import com.zy.explore.license.interfaces.frm.CommonIdFrm;
import com.zy.explore.license.interfaces.frm.LoginFrm;
import com.zy.explore.license.interfaces.frm.ModifyPwdFrm;
import com.zy.explore.license.interfaces.frm.SysUserFrm;
import com.zy.explore.license.interfaces.vo.LoginSuccessVO;
import com.zy.explore.license.interfaces.vo.PageVO;
import com.zy.explore.license.interfaces.vo.ResultVO;
import com.zy.explore.license.interfaces.vo.SysUserVO;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;

/**
 * 系统用户表(表sys_user)控制器
 *
 * @author ZY
 * @date 2021-04-28 23:31:55
 */
@Slf4j
@Api(tags = "SysUser控制器")
@RestController
@RequestMapping("/sysUser")
public class SysUserFacade {

    /**
     * token失效时间 默认30分钟(单位：分钟)
     */
    @Value("${token.expire:30}")
    private Integer tokenExpire;

    /**
     * 注入服务
     */
    @Resource
    private SysUserAssembler assembler;

    @Resource
    private SysEventLogAssembler sysEventLogAssembler;

    /**
     * 新增数据
     *
     * @param frm 待新增的frm对象
     * @return 成功返回新增后的VO对象，失败返回null
     */
    @ApiOperationSupport(order = 10)
    @ApiOperation("新增数据")
    @PostMapping("/insert")
    public SysUserVO insert(@RequestBody SysUserFrm frm) {
        return assembler.insert(frm);
    }

    /**
     * 删除数据
     *
     * @param frm 主键frm对象
     * @return 1:删除成功 其他:删除失败
     */
    @ApiOperationSupport(order = 20)
    @ApiOperation("删除数据")
    @PutMapping("/delete")
    public boolean delete(@RequestBody CommonIdFrm frm) {
        return assembler.delete(frm);
    }

    /**
     * 更新数据
     *
     * @param frm 待更新的frm对象
     * @return 成功返回更新后的VO对象，失败返回null
     */
    @ApiOperationSupport(order = 30)
    @ApiOperation("更新数据")
    @PostMapping("/update")
    public SysUserVO update(@RequestBody SysUserFrm frm) {
        return assembler.update(frm);
    }

    /**
     * 通过主键查询单条数据
     *
     * @param frm 主键frm对象
     * @return 成功返回对应ID的VO对象，失败返回null
     */
    @ApiOperationSupport(order = 40)
    @ApiOperation("根据主键查询数据")
    @GetMapping("/getById")
    public SysUserVO getById(@SpringQueryMap CommonIdFrm frm) {
        return assembler.findById(frm);
    }

    /**
     * 根据条件获取数据集
     *
     * @param frm 查询条件对象
     * @return 满足条件的数据集合
     */
    @ApiOperationSupport(order = 50)
    @ApiOperation("根据条件查询数据集")
    @GetMapping("/getList")
    public List<SysUserVO> getList(@SpringQueryMap SysUserFrm frm) {
        return assembler.getList(frm);
    }

    /**
     * 根据条件查询数据分页
     *
     * @param frm 查询条件参数
     * @return 成功返回满足条件的分页，失败返回空页
     */
    @ApiOperationSupport(order = 60)
    @ApiOperation("根据条件查询数据分页")
    @GetMapping("/getPageInfo")
    public PageVO<SysUserVO> getPageInfo(@SpringQueryMap SysUserFrm frm) {
        return assembler.getPageInfo(frm);
    }

    /**
     * 用户登录
     *
     * @param frm 用户名、密码参数对象
     * @return 返回登陆信息
     */
    @ApiOperationSupport(order = 70)
    @ApiOperation("用户登录")
    @PostMapping("/login")
    @LoginToken
    public LoginSuccessVO login(@RequestBody @Valid LoginFrm frm, HttpServletRequest request) {
        SysUser user = assembler.getUserByUsername(frm.getUsername());
        LoginSuccessVO loginSuccessVO;
        if (user == null) {
            throw MessageCode.USERNAME_PWD_ERROR.toException();
            // 若数据库中无此用户名，则新增记录(相当于注册)
//            this.initDefault(frm);
//            assembler.insert(frm);
//            user = assembler.getUserByUsername(frm.getUsername());
//            loginSuccessVO = getLoginSuccessVO(frm, user);
//            sysEventLogAssembler.recordEvent(user.getId(), IpUtil.getIpAddress(request), 5, "新用户登录", JSON.toJSONString(frm), "成功");
        } else {
            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            String password = user.getPassword();
            if (!encoder.matches(frm.getPassword(), password)) {
                sysEventLogAssembler.recordEvent(0, IpUtil.getIpAddress(request), 1, "老用户登录", JSON.toJSONString(frm), "失败");
                throw MessageCode.USERNAME_PWD_ERROR.toException();
            }
            loginSuccessVO = getLoginSuccessVO(frm, user);
            sysEventLogAssembler.recordEvent(user.getId(), IpUtil.getIpAddress(request), 1, "老用户登录", JSON.toJSONString(frm), "成功");
        }
        return loginSuccessVO;
    }

    private void initDefault(SysUserFrm frm) {
        frm.setName(FakerUtil.fakerBeautyName());
        if (StrUtil.isMobileNumber(frm.getUsername())) {
            frm.setPhone(frm.getUsername());
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        frm.setPassword(encoder.encode(frm.getPassword()));
        frm.setAvatar("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3701370651,2867135978&fm=26&gp=0.jpg");
    }

    private LoginSuccessVO getLoginSuccessVO(LoginFrm frm, SysUser user) {
        long expireAt = System.currentTimeMillis() + tokenExpire * 60 * 1000;

        String token = JwtUtil.createJWT(tokenExpire * 60, user);
        log.info("token: {} 过期时间为：{}", token, DateUtil.format(new Date(expireAt), "yyyy-MM-dd HH:mm:ss"));
        user.setPassword("");
        SysUserVO userVO = SysUserAssembler.convertToVO(user);
        // 查询用户角色
        List<SysRole> roleList = assembler.getUserRoleList(user.getId());
        userVO.setRoles(roleList);
        // 查询用户菜单
        List<SysMenu> menuList = assembler.getUserMenuList(user.getId());
        userVO.setMenus(menuList);
        // 查询用户上次登录时间和IP
        userVO.setLastLoginInfo(assembler.getLastLoginInfo(user.getId()));
        LoginSuccessVO loginSuccessVO = LoginSuccessVO.builder().user(userVO).token(token).expireAt(expireAt).build();
        frm.setPassword("******");
        return loginSuccessVO;
    }

    @ApiOperationSupport(order = 80)
    @ApiOperation("校验密码是否正确")
    @PostMapping("/checkPwd")
    public ResultVO<Integer> checkPwd(@RequestBody @Valid CheckPwdFrm frm) {
        return ResultVO.getSuccess(assembler.checkPwd(frm));
    }

    @ApiOperationSupport(order = 90)
    @ApiOperation("修改密码")
    @PostMapping("/modifyPwd")
    public ResultVO<Integer> modifyPwd(@RequestBody @Valid ModifyPwdFrm frm) {
        return ResultVO.getSuccess(assembler.modifyPwd(frm));
    }

}